package com.bit.cfdi.web.vm.productservices;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.Validator;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

import com.bit.cfdi.web.domain.ComprobanteConcepto;
import com.bit.cfdi.web.domain.Concepto;
import com.bit.cfdi.web.domain.ConceptoParte;
import com.bit.cfdi.web.domain.Negocio;
import com.bit.cfdi.web.domain.UnidadMedida;
import com.bit.cfdi.web.services.ConceptoService;
import com.bit.cfdi.web.services.UnidadMedidaService;
import com.bit.cfdi.web.session.SessionUtils;
import com.bit.cfdi.web.validators.common.DoubleValuesValidator;

@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
public class ProductosServiciosViewModel {
	
	private Logger log = LogManager.getLogger(this.getClass().getName());
	private Concepto concepto;
	private List<Concepto> conceptos;
	private List<Concepto> resultListFromSearch = null;
	private Concepto selectedConcept;
	private Concepto queryItem;
	private List<ConceptoParte> partes;
	private List<UnidadMedida> medidas;
	
	private boolean showCreateNewItem = true; 
	private boolean showInformationItem = true;
	private boolean addDetailsToItem;
	
	private boolean goAway = false;
	private boolean editItem = false;
	
	private Calendar since;
	private Calendar to;
	
	private String comprasTotales= "N/A";
	private String notas = "N/A";
	private String facturas = "N/A";
	private String compraPromedio = "N/A";

	private String mostPurchasedItem1 = "N/A";
	private String mostPurchasedItem2 = "N/A";
	private String mostPurchasedItem3 = "N/A";
	private String mostPurchasedItem4 = "N/A";
	private String mostPurchasedItem5 = "N/A";
	private String mostPurchasedItem6 = "N/A";

	private String descripcionMessageError;
	private String precioCompraMessageError;
	private String precioVentaMessageError;
	private String unidadMessageError;
	private String numeroIdentificacionMessageError;
	
	private boolean descripcionValida;
	private boolean precioCompraValido;
	private boolean precioVentaValido;
	private boolean unidadValida;
	private boolean numeroIdentificacionValida;
	
	private String unidadMedida;
	
	private Window window;
	
	@WireVariable private SessionUtils sessionUtils;
	@WireVariable private ConceptoService conceptoService;

	@WireVariable private UnidadMedidaService medidaService;
	
	private DoubleValuesValidator precioCompraValidator;
	private DoubleValuesValidator precioVentaValidator; 
	
	private boolean editCustomerData;
	
	private String textToSearch;
	/*--*/
	
	
	@Init
	public void init(@ContextParam(ContextType.EXECUTION) Execution exe) {
		@SuppressWarnings("unchecked")
		Map<String, Object> args = (Map<String, Object>) exe.getArg();
		log.info("INIT");
		precioCompraValidator = new DoubleValuesValidator("precioCompra");
		precioVentaValidator = new DoubleValuesValidator("precioVenta");
		initObjects();
	}

	
	@Command
	@NotifyChange("*")
	public void findItems() {
		if (textToSearch != null && !textToSearch.isEmpty()) {
			conceptoService.searchConceptByAllFields(
					(Negocio)sessionUtils.getFromSession(SessionUtils.NEGOCIO), textToSearch);
			if (resultListFromSearch != null && !resultListFromSearch.isEmpty()) {
				conceptos = resultListFromSearch;
			}
		} else {
			loadItems();
		}
	}
	
	@GlobalCommand
	public void displayProductServicesWindow() {
		if(window != null) {
			window.setVisible(false);
			window = null;
		}
	}
	
	@Command 
	public void exportFile() {
		Window window =(Window)Executions.createComponents(
			"/home/productos/modalWindowExportFile.zul", null, null);
		window.doModal();
	}
	
	private void initObjects() {
		concepto = new Concepto();
		Concepto c = new Concepto();
		c.setNumIdentificacion("15236548852 ");
		c.setDescripcion("item de prueba");
		c.setCodigoBarras("85632145698714");
		c.setPrecioVenta(200.0);
		c.setPrecioCompra(150.0);
		c.setUnidad("pza");
		goAway = false;
		conceptos = new ArrayList<Concepto>();
		conceptos.add(c);		
		Concepto cn = new Concepto();
		cn.setComprobanteConceptos(new HashSet<ComprobanteConcepto>());
		cn.setConceptoPartes(new HashSet<ConceptoParte>());
		medidas = medidaService.getAll();
	}

	@Command
	public void performExcelExportation() {
		Messagebox.show("¿Deséa exportar los clientes a un archivo de excel?","Question",
				Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION, new EventListener<Event>() {
					@Override public void onEvent(Event event) throws Exception {
						if (((Integer) event.getData()).intValue() == Messagebox.OK) {
							BindUtils.postGlobalCommand(null, null, "performCustomerExportation", null);
							return;
						}
					}
				});
	}

	@GlobalCommand
	public void performCustomerExportation() {
		try {
			String path = "productoservicios.xls";
			FileOutputStream out = new FileOutputStream(path);
			Workbook wb = new HSSFWorkbook();
			Sheet s = wb.createSheet();
			Row r = null;
			Cell c = null;
			int row = 0;
			r = s.createRow(row);
			c = r.createCell(0);
			c.setCellValue("Número de identificación");
			c = r.createCell(1);
			c.setCellValue("Descripción");
			c = r.createCell(2);
			c.setCellValue("Código de Barras");
			c = r.createCell(3);
			c.setCellValue("Precio de compra");
			c = r.createCell(4);
			c.setCellValue("Precio de venta");
			c = r.createCell(5);
			c.setCellValue("Unidad");
			
			row++;
			for (Concepto concepto : conceptos) {
				r = s.createRow(row);
				c = r.createCell(row);
				c = r.createCell(0);
				c.setCellValue(concepto.getNumIdentificacion());
				c = r.createCell(1);				
				c.setCellValue(concepto.getDescripcion());
				c = r.createCell(2);
				c.setCellValue(concepto.getCodigoBarras());
				c = r.createCell(3);
				c.setCellValue(concepto.getPrecioCompra());
				c = r.createCell(4);
				c.setCellValue(concepto.getPrecioVenta());
				c = r.createCell(5);
				c.setCellValue(concepto.getUnidad());
				row ++;
			}
			wb.write(out);
			out.close();
			File file = new File(path);
			Filedownload.save(file, null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}	
	
	@GlobalCommand
	@NotifyChange("*")
	public void proccessItemParts(@BindingParam("partes") List<ConceptoParte> conceptoPartes) {
		partes = conceptoPartes;
		Set<ConceptoParte> partes = new HashSet<ConceptoParte>();
		for (ConceptoParte conceptoParte : conceptoPartes) {
			partes.add(conceptoParte);
		}
		concepto.setConceptoPartes(partes);
	}
	
	@Command
	public void showItemForm() {
		boolean goAway = true;
		if (concepto.getDescripcion() == null ||  concepto.getDescripcion().isEmpty()) {
			goAway = false;
			Messagebox.show("Por favor agregue una descripción al producto ");
			return;
		} if (concepto.getUnidad() == null || concepto.getUnidad().isEmpty()) {
			goAway = false;
			Messagebox.show("Por favor especifique la unidad del producto ");
			return;			
		}
		if (goAway) {
			Map <String, Object> objList = new HashMap<String, Object>();
			objList.put("concepto", concepto);
			window =(Window)Executions.createComponents(
				"/home/productos/modalWindowAddParte.zul", null, objList);
			window.doModal();			
		}
	}
	
	@Command
	@NotifyChange("*")
	public void saveOrUpdateNewItem() {
		Negocio  negocio = (Negocio) sessionUtils.getFromSession(SessionUtils.NEGOCIO);
		if (negocio != null) {
			List<Concepto> item = conceptoService.getByDescr(negocio, concepto.getDescripcion());
			
			if (!editCustomerData) {
				if ((item != null && item.isEmpty())) {/*
					isRfcValid();
					isRazonSocialValid();
					isPaisValid();
					isCiudadValid();
					isCodigoPostalValid();*/
					if (goAway) {
						concepto.getCodigoBarras();
						concepto.getDescripcion();
					}
				} else {
					Messagebox.show("ya existe un usuario registrado con los mismos datos");
					goAway = false;
				}				
			} else {/*
				clienteService.save(cliente);
				Messagebox.show("Se ha actualizado correctamente la información del cliente");
				clientes.clear();*/
				editCustomerData = false;
			}
		}
		initObjects();
	}	
	
	@Command
	public void importFile() {
		Window window =(Window)Executions.createComponents(
			"/home/productos/modalWindowImportFile.zul", null, null);
		window.doModal();
	}

	private void loadItems() {
		conceptos = conceptoService.getAllfromNegocio(
				(Negocio)sessionUtils.getFromSession(SessionUtils.NEGOCIO));
		if (conceptos != null && !conceptos.isEmpty()) {
			selectedConcept = conceptos.get(0);
			
		}
	}	
	
	@Command
	@NotifyChange("showCreateNewItem, showInformationItem")
	public void showCreateNewItem() {
		this.showCreateNewItem = true;
		this.showInformationItem = false;
	}
	
	@Command
	@NotifyChange("*")
	public void getUserData() {

 		if (selectedConcept != null ) {
 			conceptoService.getAllfromNegocio((Negocio)sessionUtils.getFromSession(SessionUtils.NEGOCIO));
 			/* Cliente cliente = clienteService.getClienteByNegocioAndRFC(
					((Negocio) sessionUtils.getFromSession(
							SessionUtils.NEGOCIO)).getIdNegocio(),
							selectedClient.getDatosFiscales().getRfc());
			 if (cliente != null) {
				 queryToClient = cliente;
				 showCustomerDetails = true;
				 showNewCustomerForm = false;
			}*/
		}
	}	
	
	@Command
	@NotifyChange("*")
	public void editSelectedItem() {

	}
	
	@Command
	@NotifyChange("*")
	public void deleteSelectedItem() {
		
	}
	
	public List<Concepto> getConceptos() {
		return conceptos;
	}

	public void setConceptos(List<Concepto> conceptos) {
		this.conceptos = conceptos;
	}

	public Concepto getSelectedConcept() {
		return selectedConcept;
	}

	public void setSelectedConcept(Concepto selectedConcept) {
		this.selectedConcept = selectedConcept;
	}

	public Concepto getQueryItem() {
		return queryItem;
	}

	public void setQueryItem(Concepto queryItem) {
		this.queryItem = queryItem;
	}

	public boolean isShowCreateNewItem() {
		return showCreateNewItem;
	}

	public void setShowCreateNewItem(boolean showCreateNewItem) {
		this.showCreateNewItem = showCreateNewItem;
	}

	public boolean isShowInformationItem() {
		return showInformationItem;
	}

	public void setShowInformationItem(boolean showInformationItem) {
		this.showInformationItem = showInformationItem;
	}

	public boolean isAddDetailsToItem() {
		return addDetailsToItem;
	}

	public void setAddDetailsToItem(boolean addDetailsToItem) {
		this.addDetailsToItem = addDetailsToItem;
	}

	public boolean isEditItem() {
		return editItem;
	}

	public void setEditItem(boolean editItem) {
		this.editItem = editItem;
	}

	public Calendar getSince() {
		return since;
	}

	public void setSince(Calendar since) {
		this.since = since;
	}

	public Calendar getTo() {
		return to;
	}

	public void setTo(Calendar to) {
		this.to = to;
	}

	public String getComprasTotales() {
		return comprasTotales;
	}

	public void setComprasTotales(String comprasTotales) {
		this.comprasTotales = comprasTotales;
	}

	public String getNotas() {
		return notas;
	}

	public void setNotas(String notas) {
		this.notas = notas;
	}

	public String getFacturas() {
		return facturas;
	}

	public void setFacturas(String facturas) {
		this.facturas = facturas;
	}

	public String getCompraPromedio() {
		return compraPromedio;
	}

	public void setCompraPromedio(String compraPromedio) {
		this.compraPromedio = compraPromedio;
	}

	public String getMostPurchasedItem1() {
		return mostPurchasedItem1;
	}

	public void setMostPurchasedItem1(String mostPurchasedItem1) {
		this.mostPurchasedItem1 = mostPurchasedItem1;
	}

	public String getMostPurchasedItem2() {
		return mostPurchasedItem2;
	}

	public void setMostPurchasedItem2(String mostPurchasedItem2) {
		this.mostPurchasedItem2 = mostPurchasedItem2;
	}

	public String getMostPurchasedItem3() {
		return mostPurchasedItem3;
	}

	public void setMostPurchasedItem3(String mostPurchasedItem3) {
		this.mostPurchasedItem3 = mostPurchasedItem3;
	}

	public String getMostPurchasedItem4() {
		return mostPurchasedItem4;
	}

	public void setMostPurchasedItem4(String mostPurchasedItem4) {
		this.mostPurchasedItem4 = mostPurchasedItem4;
	}

	public String getMostPurchasedItem5() {
		return mostPurchasedItem5;
	}

	public void setMostPurchasedItem5(String mostPurchasedItem5) {
		this.mostPurchasedItem5 = mostPurchasedItem5;
	}

	public String getMostPurchasedItem6() {
		return mostPurchasedItem6;
	}

	public void setMostPurchasedItem6(String mostPurchasedItem6) {
		this.mostPurchasedItem6 = mostPurchasedItem6;
	}

	public Concepto getConcepto() {
		return concepto;
	}

	public void setConcepto(Concepto concepto) {
		this.concepto = concepto;
	}

	public String getTextToSearch() {
		return textToSearch;
	}

	public void setTextToSearch(String textToSearch) {
		this.textToSearch = textToSearch;
	}

	@Command @NotifyChange("descripcionValidaMessageError")
	public boolean isDescripcionValida() {
		return descripcionValida;
	}

	@Command @NotifyChange("precioCompraValidoMessageError")
	public boolean isPrecioCompraValido() {
		return precioCompraValido;
	}

	@Command @NotifyChange("precioVentaValidoMessageError")
	public boolean isPrecioVentaValido() {
		return precioVentaValido;
	}

	@Command @NotifyChange("unidadValidaMessageError")
	public boolean isUnidadValida() {
		return unidadValida;
	}

	@Command @NotifyChange("numeroIdentificacionMessageError")
	public boolean isNumeroIdentificacionValida() {
		return numeroIdentificacionValida;
	}

	public String getDescripcionMessageError() {
		return descripcionMessageError;
	}


	public void setDescripcionMessageError(String descripcionMessageError) {
		this.descripcionMessageError = descripcionMessageError;
	}


	public String getPrecioCompraMessageError() {
		return precioCompraMessageError;
	}

	public void setPrecioCompraMessageError(String precioCompraMessageError) {
		this.precioCompraMessageError = precioCompraMessageError;
	}

	public String getPrecioVentaMessageError() {
		return precioVentaMessageError;
	}

	public void setPrecioVentaMessageError(String precioVentaMessageError) {
		this.precioVentaMessageError = precioVentaMessageError;
	}

	public String getUnidadMessageError() {
		return unidadMessageError;
	}

	public void setUnidadMessageError(String unidadessageError) {
		this.unidadMessageError = unidadMessageError;
	}

	public String getNumeroIdentificacionMessageError() {
		return numeroIdentificacionMessageError;
	}

	public void setNumeroIdentificacionMessageError(
			String numeroIdentificacionMessageError) {
		this.numeroIdentificacionMessageError = numeroIdentificacionMessageError;
	}

	public Validator getPrecioCompraValidator() {
		return precioCompraValidator;
	}

	public Validator getPrecioVentaValidator() {
		return precioVentaValidator;
	}

	public List<UnidadMedida> getMedidas() {
		return medidas;
	}

	public void setMedidas(List<UnidadMedida> medidas) {
		this.medidas = medidas;
	}

	public String getUnidadMedida() {
		return unidadMedida;
	}

	public void setUnidadMedida(String unidadMedida) {
		this.unidadMedida = unidadMedida;
	}

}